package com.ste.client.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.table.DefaultTableModel;

import com.ste.client.View;
import com.ste.client.View.LimitType;
import com.ste.domain.Stock;
import com.ste.server.command.Trade.OrderType;

public class CommandsHandler {
	public ClientMessages clientMessages = new ClientMessages();
	private List<String[]> unverified = new ArrayList<String[]>();
	private View view;
	private final String tradeWithPriceTempl = "35=D|11=%s|55=%s|54=%s|38=%s|44=%s|40=2";
	private final String tradeOnMarketTempl = "35=D|11=%s|55=%s|54=%s|38=%s|40=1";

	private Integer orderCount = 0;
	private String clientName;
	private String tmpClientName;

	public CommandsHandler(View view) {
		this.view = view;
	}

	public void createOrder(Stock stock, String quantity, OrderType orderType, LimitType limitType, String limit) throws IllegalAccessException {
		List<String> newOrder = new ArrayList<String>();
		String orderId = clientName + ":" +  orderCount++;
		newOrder.add(orderId);
		newOrder.add(stock.name());
		newOrder.add(orderType.name());
		newOrder.add(quantity);
		if (clientName != null) {
			if (LimitType.LIMIT.equals(limitType)) {
				clientMessages.addMessage(String.format(tradeWithPriceTempl, orderId, stock.name(), orderType.value.toString(), quantity, limit));
				newOrder.add(limit);
			} else {
				clientMessages.addMessage(String.format(tradeOnMarketTempl, orderId, stock.name(), orderType.value.toString(), quantity));
				newOrder.add(null);
			}
			unverified.add(newOrder.toArray(new String[newOrder.size()]));
		} else {
			throw new IllegalAccessException("Client not registrated");
		}
	}

	public void processResponse(String message) {
		if (match("35=A", message)) {
			clientName = tmpClientName;
			view.loginFrame.setVisible(false);
			return;
		}
		if (match("35=A\\|49=Client", message)) {
			tmpClientName = null;
			view.getStatusLog().setText("Client with this name already logged in");
			return;
		}
		if (match("35=3\\|11=(.*)\\|373=9", message)) {
			Pattern pattern = Pattern.compile("35=3\\|11=(.*)\\|373=9");
			Matcher matcher = pattern.matcher(message);
			if (matcher.matches()) {
				String[] rejectedOrder = findUnverifiedOrder(matcher.group(1));
				view.rejectOrder(rejectedOrder);
			}
			return;
		}
		if (match("35=8\\|11=(.*)\\|39=0", message)) {
			Pattern pattern = Pattern.compile("35=8\\|11=(.*)\\|39=0");
			Matcher matcher = pattern.matcher(message);
			if (matcher.matches()) {
				String[] newOrder = findUnverifiedOrder(matcher.group(1));
				if (newOrder == null)
					return;
				List<String> tmp = new ArrayList<String>(Arrays.asList(newOrder));
				if (LimitType.MARKET.name().equals(newOrder[2])) {
					tmp.add(" ");
				}
				tmp.add(Status.NEW.name());
				view.addOrder(tmp.toArray(new String[tmp.size()]));
			}
			view.clearOrderFields();
		}

		if (match("35=8\\|11=(.*)\\|31=(.*)\\|32=(.*)\\|448=(.*)\\|39=(.*)", message)) {
			Pattern pattern = Pattern.compile("35=8\\|11=(.*)\\|31=(.*)\\|32=(.*)\\|448=(.*)\\|39=(.*)");
			Matcher matcher = pattern.matcher(message);
			if (matcher.matches()) {
				String orderId = matcher.group(1);
				String limit = matcher.group(2);
				String quantity = matcher.group(3);
				Integer statusType = Integer.valueOf(matcher.group(5));
				DefaultTableModel defaultTableModel = (DefaultTableModel) view.ordersTable.getModel();

				for (int i = 0; i < defaultTableModel.getRowCount(); i++) {
					if (defaultTableModel.getValueAt(i, 0).equals(orderId)) {
						defaultTableModel.setValueAt(quantity, i, 3);
						defaultTableModel.setValueAt(limit, i, 4);
						defaultTableModel.setValueAt(statusType == 1 ? Status.PARTLY.name() : Status.FILLED.name(), i, 5);
						return;
					}
				}
			}
		}
	}

	private String[] findUnverifiedOrder(String group) {
		for (String[] strings : unverified) {
			if (strings[0].equals(group)) {
				unverified.remove(strings);
				return strings;
			}
		}
		return null;
	}

	private boolean match(String regexp, String message) {
		return Pattern.matches(regexp, message);
	}

	enum Status {
		NEW, PARTLY, FILLED;
	}

	public void registerClient(String text) {
		view.getStatusLog().setText("");
		tmpClientName = text;
		clientMessages.addMessage("35=A|49=" + text);
	}

	public String getClientName() {
		return clientName;
	}

	public void setClientName(String clientName) {
		this.clientName = clientName;
	}
	
}
